﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;
using System.Windows.Resources;
using System.Xml.Linq;
using System.Xml;

namespace TTApp.Phone.Silverlight.Hexagons
{
    /// <summary>
    /// Đại diện cho 1 người chơi, hoặc có thể là máy.
    /// 
    /// Một người chơi gồm có tên, tập các Hexagon đang được sở hữu bởi người chơi này.
    /// </summary>
    public class Player : INotifyPropertyChanged
    {
        #region //----------------------------- Class Private Fields --------------------------------------//
        private string _name = "_unnamed";
        private int _highScore;
        private Image _hexagonImage;
        private List<Hexagon> _hexagonList = new List<Hexagon>();
        private int _score;
        #endregion

        #region //----------------------------- Public Event Delegates ------------------------------------//
        /// <summary>
        /// Phát ra khi điểm số thay đổi.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region //----------------------------- Class Public Constructors ---------------------------------//
        /// <summary>
        /// Khởi tạo 1 đối tượng người chơi mới với tên mặc định là _unnamed
        /// và ảnh mặc định của Hexagon là màu tím.
        /// </summary>
        public Player()
        {
            _highScore = 0;

            _hexagonImage = new Image();
            _hexagonImage.Source = new ImageConverter().
                ConvertFrom("/Assets/Images/Hexagon_Violet.png") as ImageSource;
        }

        /// <summary>
        /// Tạo 1 đối tượng người chơi mới với tên được truyền vào.
        /// </summary>
        /// <param name="name">Tên của người chơi.</param>
        public Player(string name) 
            : this()
        {
            _name = name;
        }

        /// <summary>
        /// Tạo 1 đối tượng người chơi mới với tên và ảnh của hexagon.
        /// </summary>
        /// <param name="name">Tên của người chơi.</param>
        /// <param name="hexagonImage"></param>
        public Player(string name, Image hexagonImage)
            : this(name)
        {
            _hexagonImage = hexagonImage;
        }
        #endregion

        #region //----------------------------- Class CLR Properties --------------------------------------//
        /// <summary>
        /// Lấy hoặc gán tên của người chơi.
        /// </summary>
        public string PlayerName
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Lấy hoặc gán HighScore của người chơi.
        /// </summary>
        public int HighScore
        {
            get { return _highScore; }
            set { _highScore = value; }
        }

        /// <summary>
        /// Hình ảnh thể hiện Hexagon bị người chơi này nắm giữ.
        /// </summary>
        [TypeConverter(typeof(ImageConverter))]
        public Image HexagonImage
        {
            get { return _hexagonImage; }
            set { _hexagonImage = value; }
        }

        /// <summary>
        /// Lấy tập Hexagon đang được sở hữu bởi người chơi này.
        /// </summary>
        public List<Hexagon> Hexagons
        {
            get { return _hexagonList; }
        }

        /// <summary>
        /// Lấy hoặc gán điểm của người chơi.
        /// </summary>
        public int Score
        {
            get
            {
                return _score;
            }
            set
            {
                if (value != _score)
                {
                    _score = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Score"));
                }
            }
        }
        #endregion

        #region //----------------------------- Protected Event Invokers ----------------------------------//
        /// <summary>
        /// Thông báo thay đổi thuộc tính cho subscribers.
        /// </summary>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, args);
            }
        }
        #endregion

        #region //----------------------------- Class Public Methods --------------------------------------//
        /// <summary>
        /// Lấy quyển sở hữu Hexagon. Đổi chủ cũ của Hexagon nếu nó đã bị sở hữu bởi người chơi khác.
        /// Hình ảnh thể hiện của Hexagon cũng bị thay đổi tương ứng với người chơi này.
        /// </summary>
        /// <param name="hexagon">Hexagon bị chiếm giữ.</param>
        public void Seize(Hexagon hexagon)
        {
            if (hexagon == null)
            {
                throw new ArgumentException("hexagon", "Hexagon phải khác null.");
            }

            // Hexagon chưa có chủ -> ăn luôn.
            if (hexagon.Owner == null)
            {
                if (!_hexagonList.Contains(hexagon))
                {
                    _hexagonList.Add(hexagon);
                    hexagon.Image = _hexagonImage;
                    hexagon.Owner = this;
                    Score++;
                }
            }
            // Trước khi ăn thì phải bỏ chủ cũ của Hexagon đi đã.
            else
            {
                Player oldOwner = hexagon.Owner;
                oldOwner.Release(hexagon);

                if (!_hexagonList.Contains(hexagon))
                {
                    _hexagonList.Add(hexagon);
                    hexagon.Image = _hexagonImage;
                    hexagon.Owner = this;
                    Score++;
                }
            }
        }

        /// <summary>
        /// Bỏ quyền sở hữu đối với Hexagon này.
        /// </summary>
        /// <param name="hexagon">Hexagon sẽ được tự do.</param>
        public void Release(Hexagon hexagon)
        {
            if (hexagon == null)
            {
                throw new ArgumentException("hexagon", "Hexagon phải khác null.");
            }

            if (_hexagonList.Contains(hexagon))
            {
                _hexagonList.Remove(hexagon);
                hexagon.Owner = null;
                Score--;
            }
        }

        /// <summary>
        /// Kiểm tra xem người chơi hiện tại có sở hữu Hexagon này hay không.
        /// </summary>
        /// <param name="hexagon">Hexagon được kiểm tra.</param>
        /// <returns>true nếu người chơi có sở hữu Hexagon này.</returns>
        public bool IsOwn(Hexagon hexagon)
        {
            return _hexagonList.Contains(hexagon);
        }

        /// <summary>
        /// Kiểm tra xem ở lượt đi này, người chơi có thể đánh được nước này hay không.
        /// </summary>
        /// <returns>true nếu có thể đi được 1 nước nào đó, false nếu ngược lại.</returns>
        public bool CanMove()
        {
            foreach (Hexagon hexagon in _hexagonList)
            {
                if (hexagon.GetMovableSlot().Count != 0)
                {
                    return true;
                }
            }

            return false;
        }
        #endregion

        #region //----------------------------- Class Static Methods --------------------------------------//
        /// <summary>
        /// Lấy danh sách người chơi từ file xml. Trong danh sách có thể kèm theo Hexagon mặc định mà 
        /// người chơi này sở hữu.
        /// </summary>
        /// <param name="pathToXml">Đường dẫn tới file XML.</param>
        /// <param name="board">Đối tượng bàn cờ chứa các Hexagon.</param>
        /// <returns></returns>
        public static List<Player> LoadFile(string pathToXml, Board board)
        {
            List<Player> playerList = new List<Player>();

            // Đường dẫn đến file xml. Mặc định là ở TTApp.Phone.Silverlight.Hexagons.dll
            Uri uri = new Uri(String.Format("/TTApp.Phone.Silverlight;component/{0}", pathToXml), UriKind.Relative);
            StreamResourceInfo resourceInfo = Application.GetResourceStream(uri);

            // Tạo đối tượng LINQ to XML
            XDocument document = XDocument.Load(resourceInfo.Stream);

            XElement rootElement = document.Root;
            if (rootElement.Name.LocalName == "MapData")
            {
                XElement playersElement = XmlUtils.GetUniqueChildElement(rootElement, "Players");
                playerList = GetPlayerList(playersElement, board);
            }
            else
            {
                throw new XmlException("Gốc phải là tag <MapData>");
            }

            return playerList;
        }

        /// <summary>
        /// Tạo các đối tượng người chơi từ tag <Players></Players>
        /// </summary>
        /// <param name="playersElement"></param>
        /// <param name="board"></param>
        /// <returns></returns>
        private static List<Player> GetPlayerList(XElement playersElement, Board board)
        {
            List<Player> playerList = new List<Player>();

            foreach (XElement playerElement in playersElement.Elements("Player"))
            {
                Player player = new Player();
                SetPlayerAttribute(playerElement, player);

                // Lấy Hexagon cho người chơi.
                XElement hexagonsElement = XmlUtils.GetUniqueChildElement(playerElement, "Hexagons");
                SetPlayerHexagons(hexagonsElement, player, board);

                playerList.Add(player);
            }

            foreach (XElement aiPlayerElement in playersElement.Elements("AIPlayer"))
            {
                AIPlayer aiPlayer = new AIPlayer();
                SetPlayerAttribute(aiPlayerElement, aiPlayer);

                // Lấy Hexagon cho AI
                XElement hexagonsElement = XmlUtils.GetUniqueChildElement(aiPlayerElement, "Hexagons");
                SetPlayerHexagons(hexagonsElement, aiPlayer, board);

                playerList.Add(aiPlayer);
            }

            return playerList;
        }

        /// <summary>
        /// Thiết lập các thuộc tính (hay Properties) của Player.
        /// </summary>
        /// <param name="playerElement">Tag <Player></Player> trong file XML.</param>
        /// <param name="player">Đối tượng Player được set thuộc tính.</param>
        private static void SetPlayerAttribute(XElement playerElement, Player player)
        {
            foreach (XAttribute attribute in playerElement.Attributes())
            {
                switch (attribute.Name.LocalName)
                {
                    case "Name":
                        player.PlayerName = attribute.Value;
                        break;

                    case "Image":
                        player.HexagonImage = new ImageConverter().ConvertFrom(attribute.Value) as Image;
                        break;
                }
            }
        }

        /// <summary>
        /// Thiết lập danh sách Hexagon được sở hữu bởi người chơi.
        /// </summary>
        /// <param name="hexagonsElement">Tag <Hexagons></Hexagons> của người chơi trong file XML.</param>
        /// <param name="player">Đối tượng Player sở hữu Hexagon.</param>
        /// <param name="board">Đối tượng board chứa Hexagon.</param>
        private static void SetPlayerHexagons(XElement hexagonsElement, Player player, Board board)
        {
            foreach (XElement positionElement in hexagonsElement.Elements("Position"))
            {
                double x = Convert.ToDouble(positionElement.Attribute("X").Value);
                double y = Convert.ToDouble(positionElement.Attribute("Y").Value);

                player.Seize(board.GetHexagon(x, y));
            }
        }
        #endregion
    }
}
